//实现文件传输子服务
#include <brpc/server.h>
#include <butil/logging.h>
#include "etcd.hpp"     // 服务注册模块封装
#include "Logger.hpp"   // 日志模块封装
#include "file.pb.h"  // protobuf框架代码
#include "base.pb.h"
#include "utils.hpp"

namespace chatroom{
    // 1  brpc服务端
    class FileServiceImp : public chatroom::FileService{
    public:
        FileServiceImp(){}
        ~FileServiceImp(){}
        //单个文件的下载
        void  GetSingleFile(google::protobuf::RpcController* controller,
            const ::chatroom::GetSingleFileReq* request,
            ::chatroom::GetSingleFileRsp* response,
            ::google::protobuf::Closure* done){
                brpc::ClosureGuard guard(done);
                response->set_request_id(request->request_id());
                std::string fid = request->file_id();
                //从服务器上读取数据
                std::string body;
                bool ret = readfile(fid,body);
                if(ret == false)
                {
                    response->set_success(false);
                    response->set_errmsg("读取文件失败");
                    Logger_ERROR("{}读取文件失败",request->request_id());
                    return;
                }
                response->set_success(true);
                chatroom::FileDownloadData* info = response->mutable_file_data();
                info->set_file_id(fid);
                info->set_file_content(body);
            }
        //多文件的下载
        void GetMultiFile(google::protobuf::RpcController* controller,
            const ::chatroom::GetMultiFileReq* request,
            ::chatroom::GetMultiFileRsp* response,
            ::google::protobuf::Closure* done){
                brpc::ClosureGuard guard(done);
                response->set_request_id(request->request_id());
                for(int i = 0;i < request->file_id_list_size();i++)
                {
                    const std::string fid = request->file_id_list(i);
                    std::string body;
                    bool ret = readfile(fid,body);
                    if(ret==false)
                    {
                        response->set_success(false);
                        response->set_errmsg("多文件下载失败");
                        Logger_ERROR("{}下载失败",request->request_id());
                        return;
                    }
                    auto info = response->mutable_file_data();
                    FileDownloadData filedata;
                    filedata.set_file_id(fid);
                    filedata.set_file_content(body);
                    info->insert({fid,filedata});
                }
                response->set_success(true);
            }
        //单文件的上传
        void PutSingleFile(google::protobuf::RpcController* controller,
            const ::chatroom::PutSingleFileReq* request,
            ::chatroom:: PutSingleFileRsp* response,
            ::google::protobuf::Closure* done){
                brpc::ClosureGuard guard(done);
                response->set_request_id(request->request_id());
                //先为文件生成一个唯一的uuid，存储在服务器上
                std::string fid = uuid();
                //获取文件数据
                const std::string body =request->file_data().file_content();
                bool ret = writefile(fid,body);
                if(ret==false)
                {
                    response->set_success(false);
                    response->set_errmsg("单个文件的上传失败");
                    Logger_ERROR("{}单个文件上传失败",request->request_id());
                    return;
                }
                response->set_success(true);
                auto* info = response->mutable_file_info();
                info->set_file_id(fid);
                info->set_file_size(request->file_data().file_size());
                info->set_file_name(request->file_data().file_name());
            }
        //多文件的上传
        void PutMultiFile(google::protobuf::RpcController* controller,
            const ::chatroom::PutMultiFileReq* request,
            ::chatroom::PutMultiFileRsp* response,
            ::google::protobuf::Closure* done){
                brpc::ClosureGuard guard(done);
                response->set_request_id(request->request_id());
                for(int i = 0;i < request->file_data_size();i++)
                {
                    std::string fid = uuid();
                    //获取文件数据
                    const std::string body =request->file_data(i).file_content();
                    bool ret = writefile(fid,body);
                    if(ret==false)
                    {
                        response->set_success(false);
                        response->set_errmsg("多个文件的上传失败");
                        Logger_ERROR("{}多个文件上传失败",request->request_id());
                        return;
                    }
                    auto* info = response->add_file_info();
                    info->set_file_id(fid);
                    info->set_file_size(request->file_data(i).file_size());
                    info->set_file_name(request->file_data(i).file_name());
                }
                response->set_success(true);
            }
    };
    class fileServer{
        public:
            using ptr = std::shared_ptr<fileServer>;
            fileServer(std::shared_ptr<brpc::Server>& server,chatroom::Registery::ptr& rclient)
            :_server(server),_rclient(rclient){}
            ~fileServer(){}
            void start(){
                _server->RunUntilAskedToQuit();
            }
        private:
            std::shared_ptr<brpc::Server> _server;
            chatroom::Registery::ptr _rclient;

    };
    class fileServerBuild{
        public:
            void make_rpc_server(int32_t port,int32_t timeout,int32_t num_threads)
            {
                _server = std::make_shared<brpc::Server>();
                //3 往服务器中添加服务
                FileServiceImp* file = new FileServiceImp();
                int ret = _server->AddService(file,brpc::ServiceOwnership::SERVER_OWNS_SERVICE);
                if(ret == -1)
                {
                    Logger_ERROR("添加服务失败");
                    abort();
                }
                //4 启动服务器
                brpc::ServerOptions options;
                options.idle_timeout_sec = timeout; //指定超时连接时间，-1表示超时一直在连接着
                options.num_threads = num_threads;//cpu线程数量
                ret = _server->Start(port,&options);
                if(ret == -1)
                {
                    Logger_ERROR("启动服务器失败");
                    abort();
                }
            }
            void  make_reg_object(std::string& register_host,const std::string& hostname,std::string& access_host)
            {
                _rclient = std::make_shared<chatroom::Registery>(register_host);
                _rclient->Register(hostname,access_host);
            }
            fileServer::ptr build()
            {
                if(!_server){
                    Logger_ERROR("RPC服务子模块没有初始化");
                    abort();
                }
                if(!_rclient){
                    Logger_ERROR("注册服务没有初始化");
                    abort();
                }
                return std::make_shared<fileServer>(_server,_rclient);  
            }
        private:
            std::shared_ptr<brpc::Server> _server;
            chatroom::Registery::ptr _rclient;
    };
}